package cn.da.shuai.cool.gateway.listener;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

@Slf4j
@Component
public class NacosRouteDefinitionListener implements ApplicationEventPublisherAware {
    
    private final NacosConfigManager nacosConfigManager;
    private final RouteDefinitionWriter routeDefinitionWriter;
    private final RouteDefinitionLocator routeDefinitionLocator;
    private ApplicationEventPublisher applicationEventPublisher;
    
    private static final String DATA_ID = "gateway-routes.yml";
    private static final String GROUP = "DEFAULT_GROUP";
    
    private final ObjectMapper yamlMapper;
    
    public NacosRouteDefinitionListener(NacosConfigManager nacosConfigManager,
                                      RouteDefinitionWriter routeDefinitionWriter,
                                      RouteDefinitionLocator routeDefinitionLocator) {
        this.nacosConfigManager = nacosConfigManager;
        this.routeDefinitionWriter = routeDefinitionWriter;
        this.routeDefinitionLocator = routeDefinitionLocator;
        this.yamlMapper = new ObjectMapper(new YAMLFactory());
    }
    
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    
    @PostConstruct
    public void init() throws NacosException {
        // 初始加载路由配置
        loadRouteConfig();
        
        // 添加Nacos监听器，配置变化时自动刷新
        nacosConfigManager.getConfigService().addListener(DATA_ID, GROUP, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }
            
            @Override
            public void receiveConfigInfo(String configInfo) {
                log.info("检测到路由配置变化，准备刷新路由");
                refreshRoutes(configInfo);
            }
        });
    }
    
    /**
     * 加载路由配置
     */
    private void loadRouteConfig() {
        try {
            String configInfo = nacosConfigManager.getConfigService().getConfig(DATA_ID, GROUP, 5000);
            if (configInfo != null && !configInfo.trim().isEmpty()) {
                log.info("加载初始路由配置");
                refreshRoutes(configInfo);
            } else {
                log.warn("未找到路由配置，dataId: {}, group: {}", DATA_ID, GROUP);
            }
        } catch (NacosException e) {
            log.error("加载路由配置失败", e);
        }
    }
    
    /**
     * 刷新路由
     */
    private void refreshRoutes(String configInfo) {
        try {
            // 解析YAML配置
            GatewayRouteConfig routeConfig = yamlMapper.readValue(configInfo, GatewayRouteConfig.class);
            List<RouteDefinition> newRoutes = routeConfig.getRoutes();
            
            if (newRoutes == null) {
                newRoutes = new ArrayList<>();
            }
            
            // 清空现有路由并添加新路由
            clearRoutes();
            addRoutes(newRoutes);
            
            // 发布路由刷新事件
            applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            log.info("路由刷新成功，共 {} 个路由", newRoutes.size());
            
        } catch (Exception e) {
            log.error("刷新路由配置失败", e);
        }
    }
    
    /**
     * 清空所有路由
     */
    private void clearRoutes() {
        routeDefinitionLocator.getRouteDefinitions()
                .collectList()
                .flatMapMany(routeDefinitions -> {
                    List<Mono<Void>> deletionMonos = new ArrayList<>();
                    for (RouteDefinition routeDefinition : routeDefinitions) {
                        deletionMonos.add(routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())));
                    }
                    return Flux.merge(deletionMonos);
                })
                .then()
                .flux();
    }
    
    /**
     * 添加路由列表
     */
    private void addRoutes(List<RouteDefinition> routes) {
        if (CollectionUtils.isEmpty(routes)) {
            return;
        }
        
        for (RouteDefinition route : routes) {
            routeDefinitionWriter.save(Mono.just(route)).subscribe();
        }
    }
    
    /**
     * 内部类用于解析YAML结构
     */
    @Setter
    @Getter
    public static class GatewayRouteConfig {
        private Spring spring;

        public List<RouteDefinition> getRoutes() {
            if (spring != null && 
                spring.getCloud() != null && 
                spring.getCloud().getGateway() != null) {
                return spring.getCloud().getGateway().getRoutes();
            }
            return null;
        }
    }
    
    // 嵌套类用于映射YAML结构
    @Setter
    @Getter
    public static class Spring {
        private Cloud cloud;

    }
    
    @Setter
    @Getter
    public static class Cloud {
        private Gateway gateway;

    }
    
    @Setter
    @Getter
    public static class Gateway {
        private List<RouteDefinition> routes;

    }
}